/*****************************************************************************
*    Copyright (C)2003 Ali Corporation. All Rights Reserved.
*
*    File:    nim_cx24109.c
*
*    Description:    This file contains CX24109 basic function in LLD.
*    History:
*           Date            Athor        Version          Reason
*	    ============	=============	=========	=================
*	1.  Jun.08.2006		David Ding		 Ver 0.1	Create file.
*
*
*
*****************************************************************************/

#include <sys_config.h>
#include <retcode.h>
#include <types.h>

#include <api/libc/printf.h>
#include <api/libc/string.h>
#include <bus/i2c/i2c.h>
#include <osal/osal_task.h>
#include "nim_cx24109.h"

#define MAX_BUF_LEN 16
struct QPSK_TUNER_CONFIG_EXT *stCX24109_dev_id[MAX_TUNER_SUPPORT_NUM] = {NULL};
static UINT32 stCX24109_tuner_cnt = 0;

/*****************************************************************************
* INT32 cx24109_read(UINT8 reg,UINT8* buff,UINT8 len)
*
* Tuner read register from CX24109
*
* Arguments:
*  Parameter1: UINT8 reg		: Register offset of CX24109
*  Parameter2: UINT8* buff		: Read data buffer
*  Parameter3: UINT8 len		: Read length
*
* Return Value: INT32			: Result
*****************************************************************************/
INT32 cx24109_read(UINT32 i2c_type_id, UINT8 base_addr, UINT8 reg,UINT8* buff,UINT8 len)
{
	buff[2] = (reg&0x03)<<3;
	return i2c_write_read(i2c_type_id, base_addr, buff, 3, len);
}

/*****************************************************************************
* INT32 cx24109_write(UINT8 reg,UINT8* buff,UINT8 len)
*
* Tuner write register from CX24109
*
* Arguments:
*  Parameter1: UINT8 reg		: Register offset of CX24109
*  Parameter2: UINT8* buff		: write data buffer
*  Parameter3: UINT8 len		: write length
*
* Return Value: INT32			: Result
*****************************************************************************/
INT32 cx24109_write(UINT32 i2c_type_id, UINT8 base_addr, UINT8 reg,UINT8* buff,UINT8 len)
{
	UINT8  i, buffer[4];

	if ((len > 3) || (reg > 3))
	{
	    return ERR_FAILUE;
	}
	for (i = 0; i < len; i++)
	{
	    buffer[i] = buff[i];
	}    
    buffer[2] = (buffer[2]&0x07) + ((reg&0x03)<<3);
    
	return i2c_write(i2c_type_id, base_addr, buffer, len);
}

/*****************************************************************************
* INT32 nim_cx24109_init(UINT32 para, struct QPSK_TUNER_CONFIG_EXT * ptrTuner_Config)
*
* Tuner CX24109 Initialization
*
* Arguments:
*  Parameter1: UINT32 para		: Input Parameter
*  Parameter2: struct QPSK_TUNER_CONFIG_EXT * ptrTuner_Config		: pointer for Tuner configuration structure
*
* Return Value: INT32			: Result
*****************************************************************************/
INT32 nim_cx24109_init(UINT32* tuner_id, struct QPSK_TUNER_CONFIG_EXT * ptrTuner_Config)
{
	int i;
	UINT8 buffer[MAX_BUF_LEN];
	struct QPSK_TUNER_CONFIG_EXT * stCX24109_ptr = NULL;
	if(ptrTuner_Config == NULL||stCX24109_tuner_cnt>=MAX_TUNER_SUPPORT_NUM)
		return ERR_FAILUE;
	stCX24109_ptr = (struct QPSK_TUNER_CONFIG_EXT *)MALLOC(sizeof(struct QPSK_TUNER_CONFIG_EXT));
	if(!stCX24109_ptr)
		return ERR_FAILUE;
	stCX24109_dev_id[stCX24109_tuner_cnt] = stCX24109_ptr;
	MEMCPY(stCX24109_ptr, ptrTuner_Config, sizeof(struct QPSK_TUNER_CONFIG_EXT));
	*tuner_id = stCX24109_tuner_cnt;
	stCX24109_tuner_cnt ++;
	return SUCCESS;
}


/*****************************************************************************
* INT32 nim_cx24109_control(UINT32 freq, UINT32 sym)
*
* Tuner write operation
*
* Arguments:
*  Parameter1: UINT32 freq		: Synthesiser programmable divider
*  Parameter2: UINT32 sym			: Baseband Symbol Rate
*  Parameter3: UINT8 cp			: Charge pump current
*
* Return Value: INT32			: Result
*****************************************************************************/
INT32 nim_cx24109_control(UINT32 tuner_id, UINT32 freq, UINT32 sym)
{
    	UINT8 buffer[MAX_BUF_LEN];
    	UINT8 vco_div, band_sel; //8 bits
    	UINT8 a_div, r_div, pump_polarity, pump_current;
    	UINT16 vga1_offset, vga2_offset, vca_slop, vca_offset, n_div; //9 bits
	struct QPSK_TUNER_CONFIG_EXT * stCX24109_ptr = NULL;

	if(tuner_id>=stCX24109_tuner_cnt||tuner_id>=MAX_TUNER_SUPPORT_NUM)
		return ERR_FAILUE;
	stCX24109_ptr = stCX24109_dev_id[tuner_id];
	if( 1075 >= freq )
    	vco_div = 2;
	else
		vco_div = 0;

    if( freq < 1019 )
		band_sel = 0x40;
	else if( freq < 1075 )
		band_sel = 0x80;
	else if( freq < 1178 )
		band_sel = 0x01;
	else if( freq < 1296 )
		band_sel = 0x02;
	else if( freq < 1432 )
		band_sel = 0x04;
	else if( freq < 1576 )
		band_sel = 0x08;
	else if( freq < 1718 )
		band_sel = 0x10;
	else if( freq < 1856 )
		band_sel = 0x20;
	else if( freq < 2036 )
        band_sel = 0x40;
	else
		band_sel = 0x80;

    if(1000 < sym < 5000)
    {
        vga1_offset = 0x1f8; //-30
        vga2_offset = 0x1f8; //29
        vca_slop = 0x007; //52
        vca_offset = 0x007; //98.5
    }
    else if(sym < 15000)
    {
        vga1_offset = 0x1e0; //-33
        vga2_offset = 0x180; //17
        vca_slop = 0x01f; //57
        vca_offset  = 0x007; //98.5   
    }
    else
    {
        vga1_offset = 0x180; //-36
        vga2_offset = 0x100; //14
        vca_slop = 0x03f; //59.5
        vca_offset = 0x007; //98.5 
    }

    if(freq < 1550)
        pump_current = 1; // low 50% VCO frequency, charge pump current = 2mA
    else
        pump_current = 2; // upper 50% VCO frequency, charge pump current = 3mA

    pump_polarity = 1; // Negative
    r_div = 0x03; // Reference divider 10

    //F_vco = (F_crystal/r_div)*(n_div+(a_div/32))*32*2, if a_div = 0, n_div = n_div + 1;
    a_div = 0;
    n_div = (freq*r_div/stCX24109_ptr->wTuner_Crystal - 2*a_div)/64;
    if(a_div == 0) n_div++;
    
    //reg00, set Band Select
    MEMSET(buffer, MAX_BUF_LEN, 0);
    buffer[0] = band_sel;
    buffer[1] = vco_div;
    cx24109_write(stCX24109_ptr->i2c_type_id, stCX24109_ptr->cTuner_Base_Addr, 0x00, buffer ,3);

    //reg01, set VGA
    MEMSET(buffer, MAX_BUF_LEN, 0);
    buffer[0] = vga1_offset&0xff;
    buffer[1] = ((vga1_offset >> 8)&0x01)+ ((vga2_offset&0x7f)<<1);
    buffer[2] = (vga2_offset >> 7)&0x03;
    cx24109_write(stCX24109_ptr->i2c_type_id, stCX24109_ptr->cTuner_Base_Addr, 0x01, buffer ,3);

    //reg02, set VCA
    MEMSET(buffer, MAX_BUF_LEN, 0);
    buffer[0] = vca_slop&0xff;
    buffer[1] = ((vca_slop >> 8)&0x01)+ ((vca_offset&0x7f)<<1);
    buffer[2] = (vca_offset >> 7)&0x03;
    cx24109_write(stCX24109_ptr->i2c_type_id, stCX24109_ptr->cTuner_Base_Addr, 0x02, buffer ,3);

    //reg03, set PLL
    MEMSET(buffer, MAX_BUF_LEN, 0);
    buffer[0] = a_div + ((n_div&0x7)<<5);
    buffer[1] = ((n_div >> 3)&0x3f) + ((pump_current&0x03)<<6);
    buffer[2] = (pump_polarity&0x01) + ((r_div&0x03)<<1);
    cx24109_write(stCX24109_ptr->i2c_type_id, stCX24109_ptr->cTuner_Base_Addr, 0x03, buffer ,3);
    
	return SUCCESS;
}

/*****************************************************************************
* INT32 nim_cx24109_status(UINT8 *lock)
*
* Tuner read operation
*
* Arguments:
*  Parameter1: UINT8 *lock		: Phase lock status
*
* Return Value: INT32			: Result
*****************************************************************************/
INT32 nim_cx24109_status(UINT32 tuner_id, UINT8 *lock)
{
	if(tuner_id>=stCX24109_tuner_cnt||tuner_id>=MAX_TUNER_SUPPORT_NUM)
	{
		*lock = 0;
		return ERR_FAILUE;
	}
	/* Because CX24109 doesn't has this flag,return 1 directly */
	*lock = 1;
	return SUCCESS;
}

